home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / curses / cconq.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-04  |  24.6 KB  |  1,300 lines  |  [TEXT/KAHL]

  1. /* The main program of the curses interface to Xconq.
  2.    Copyright (C) 1986, 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. #include "cmdline.h"
  12. #include "cconq.h"
  13. int ask_direction PROTO ((char *prompt, int *dirp));
  14.  
  15. extern char *dashbuffer;
  16.  
  17. #ifdef THINK_C
  18. /* This is to get the command line reader in Think C on the Mac. */
  19. #include <console.h>
  20. #endif /* THINK_C */
  21.  
  22. int announced = FALSE;
  23.  
  24. char *announcemsg = NULL;
  25.  
  26. /* The side of the one human player. */
  27.  
  28. Side *dside = NULL;
  29.  
  30. /* move to where a change has occured */
  31.  
  32. int follow_action;
  33.  
  34. /* The location currently being examined. */
  35.  
  36. int curx, cury;
  37.  
  38. int tmpcurx, tmpcury;
  39.  
  40. /* The unit currently being examined, if any. */
  41.  
  42. Unit *curunit;
  43.  
  44. Unit *tmpcurunit;
  45.  
  46. /* The current interaction mode. */
  47.  
  48. enum mode mode;
  49.  
  50. /* The pushed interaction mode. */
  51.  
  52. enum mode prevmode;
  53.  
  54. /* The current input character. */
  55.  
  56. char inpch;
  57.  
  58. /* The command's numeric argument. */
  59.  
  60. int cmdarg;
  61.  
  62. /* These are used when asking for a unit type. */
  63.  
  64. char *ustr;
  65. int *uvec;
  66. int *bvec;
  67.  
  68. /* length and number of notice lines */
  69.  
  70. int nw, nh;
  71.  
  72. /* last current x and y (-1,-1 initially) */
  73.  
  74. int lastx, lasty;
  75.  
  76. /* current prompt on display */
  77.  
  78. char *text1;
  79. char *text2;
  80.  
  81. /* data about string under construction */
  82.  
  83. int reqstrbeg;
  84. int reqstrend;
  85.  
  86. /* The help window. */
  87.  
  88. struct ccwin *helpwin;
  89.  
  90. /* Cached help info. */
  91.  
  92. HelpNode *cur_help_node;
  93.  
  94. HelpNode *help_help_node;
  95.  
  96. HelpNode *topics_help_node;
  97.  
  98. char *helptopic;
  99.  
  100. char *helpstring;
  101.  
  102. int helpscreentop;
  103.  
  104. struct ccwin *datewin;
  105.  
  106. struct ccwin *sideswin;
  107.  
  108. struct ccwin *toplineswin;
  109.  
  110. struct ccwin *clockwin;
  111.  
  112. /* Display of a piece of the world */
  113.  
  114. struct ccwin *mapwin;
  115.  
  116. /* Unit listing */
  117.  
  118. struct ccwin *listwin;
  119.  
  120. struct ccwin *closeupwin;
  121.  
  122. struct ccwin *sidecloseupwin;
  123.  
  124. /* Map dimensions. */
  125.  
  126. int mw, mh;
  127.  
  128. VP *mvp;
  129.  
  130. /* lower left of viewport in cell coords */
  131.  
  132. int vx, vy;
  133.  
  134. /* Boundaries of viewport in cell coords */
  135.  
  136. int vw, vh;
  137.  
  138. /* 1/2 (rounded down) of above values */
  139.  
  140. int vw2, vh2;
  141.  
  142. int lastvcx, lastvcy;
  143.  
  144. /* List dimensions. */
  145.  
  146. int lw, lh;
  147.  
  148. /* Side list dimensions. */
  149.  
  150. int sh;
  151.  
  152. /* How to draw the map. */
  153.  
  154. int drawterrain;
  155.  
  156. /* Display units on the map? */
  157.  
  158. int drawunits;
  159.  
  160. /* Display unit names/numbers on the map? */
  161.  
  162. int drawnames;
  163.  
  164. int drawpeople;
  165.  
  166. enum listsides listsides;
  167. int test;
  168. int value;
  169. int sorton;
  170. int sortorder;
  171.  
  172. int active;
  173.  
  174. char *unitchars = NULL;
  175. char *terrchars = NULL;
  176. char unseen_char_1;
  177. char unseen_char_2;
  178.  
  179. /* The main program just invokes everything else. */
  180.  
  181. main(argc, argv)
  182. int argc;
  183. char *argv[];
  184. {
  185.     int tmout;
  186.  
  187. #ifdef THINK_C
  188.     /* This is how Think C picks up a command line. */
  189.     argc = ccommand(&argv);
  190. #endif
  191. #ifdef MAC
  192.     {
  193.     extern char *_maccur_pgm_name;
  194.         
  195.     _maccur_pgm_name = "Cconq";
  196.     }
  197. #endif
  198.     printf("\n              Welcome to Curses Xconq version %s\n\n",
  199.        version_string());
  200.     init_library_path(NULL);
  201.     print_any_news();
  202.     printf("%s", license_string());
  203.     clear_game_modules();
  204.     init_data_structures();
  205.     parse_command_line(argc, argv, general_options);
  206.     /* (should volunteer to restore saved game if one found) */
  207.     load_all_modules();
  208.     check_game_validity();
  209.     parse_command_line(argc, argv, variant_options);
  210.     set_variants_from_options();
  211.     parse_command_line(argc, argv, player_options);
  212.     /* Go through once more and complain about anything not used. */
  213.     parse_command_line(argc, argv, leftover_options);
  214.     set_players_from_options();
  215.     make_trial_assignments();
  216.     calculate_globals();
  217.     run_synth_methods();
  218.     final_init();
  219.     assign_players_to_sides();
  220.     /* Run through game calcs, but don't let anything move yet; this
  221.        gives display code better values to work with. */
  222.     run_game(0);
  223.     init_display();
  224.     init_interaction();
  225.     redraw();
  226.     init_signal_handlers();
  227.     while (TRUE) {
  228. #ifdef HAVE_SELECT
  229. please somebody write this code
  230.     run_game(1);
  231. #else
  232.     set_g_use_side_priority(TRUE);
  233.     /* assumes no real-timeness */
  234.     run_game(-1);
  235.     maybe_handle_input(0);
  236. #endif
  237.     }
  238. }
  239.  
  240. /* Nonempty display name not actually used, but needed to keep things
  241.    straight. */
  242.  
  243. Player *
  244. add_default_player()
  245. {
  246.     Player *player = add_player();
  247.  
  248.     player->name = getenv("USER");
  249.     player->displayname = "term";
  250.     return player;
  251. }
  252.  
  253. /* Set up the basic user interface for a side. */
  254.  
  255. void
  256. init_ui(side)
  257. Side *side;
  258. {
  259.     if (side_wants_display(side)) {
  260.     if (dside == NULL) {
  261.         side->ui = (struct a_ui *) xmalloc(sizeof(int));
  262.         dside = side;
  263.         active = FALSE;
  264.         follow_action = FALSE;
  265.         cur_help_node = NULL;
  266.         mode = prevmode = SURVEY;
  267.         cmdarg = -1;
  268.     } else {
  269.         fprintf(stderr, "More than one side wanted a display!\n");
  270.         exit(1);
  271.     }
  272.     }
  273. }
  274.  
  275. /* Open display, create all the windows we'll need, do misc setup things,
  276.    and initialize some globals to out-of-range values for recognition later. */
  277.  
  278. void
  279. init_display()
  280. {
  281.     int u, t, x, y, i, totw, toth;
  282.     char *str;
  283.  
  284.     if (dside == NULL) {
  285.     fprintf(stderr, "No side wanted a display!\n");
  286.     exit(1);
  287.     }
  288.     Dprintf("Will try to open screen as display...\n");
  289.     /* Go through the standard curses setup sequence. */
  290.     initscr();
  291.     nonl();
  292.     noecho();
  293.     cbreak();
  294.     clear();
  295.     /* Set up random globals. */
  296.     nw = min(BUFSIZE, 60);
  297.     nh = 1;
  298.     text1 = xmalloc (BUFSIZE);
  299.     text2 = xmalloc (BUFSIZE);
  300.     text1[0] = '\0';
  301.     text2[0] = '\0';
  302.     ustr = xmalloc (MAXUTYPES);
  303.     uvec = (int *) xmalloc (MAXUTYPES * sizeof(int));
  304.     bvec = (int *) xmalloc (MAXUTYPES * sizeof(int));
  305.     /* Compute the division of the screen. */
  306.     mw = (2 * COLS) / 3;
  307.     mh = LINES - 2 - INFOLINES - 1;
  308.  
  309.     mvp = new_vp();
  310.     /* Each cell is actually 2 chars or "pixels" wide.  This is the
  311.        difference from the standard power==0 parameters, so we do
  312.        a cheesy thing and tweak the array directly. */
  313.     hws[0] = 2;
  314.     set_view_power(mvp, 0);
  315.     set_view_size(mvp, mw, mh);
  316.  
  317.     lw = COLS - mw - 1;
  318.  
  319.     sh = numsides + 1;
  320.     /* The height of the list window is what's left over after making
  321.        space for the side list and status lines. */
  322.     lh = LINES - sh - 1 - 1;
  323.  
  324.     pick_a_focus(dside, &x, &y);
  325.     set_view_focus(mvp, x, y);
  326.     lastvcx = lastvcy = -1;
  327.     /* Set default values for the display controls. */
  328.     drawterrain = TRUE;
  329.     drawunits = TRUE;
  330.     drawnames = FALSE;  /* they clutter up the screen */
  331.     listsides = allsides;
  332.     curunit = NULL;
  333.     /* Create all the windows. */
  334.     toplineswin = create_window(0, 0, nw, 2);
  335.     datewin = create_window(nw, 0, COLS - nw, 1);
  336.     clockwin = create_window(nw, 1, COLS - nw, 1); 
  337.     closeupwin = create_window(0, 2, mw, INFOLINES);
  338.     mapwin = create_window(0, 2 + INFOLINES, mw, mh + 1);
  339.     sideswin = create_window(mw + 1, 2, lw, sh);
  340.     listwin = create_window(mw + 1, 2 + sh, lw, lh);
  341.     /* Help window covers the screen usually. */
  342.     helpwin = create_window(0, 0, COLS, LINES);
  343.     /* Set up the initial scroll position of the map. */
  344.     set_scroll();
  345.     /* Make a buffer full of dashes, for use on mode lines. */
  346.     if (dashbuffer == NULL) {
  347.     dashbuffer = xmalloc(COLS + 1);
  348.     for (i = 0; i < COLS; ++i)
  349.       dashbuffer[i] = '-';
  350.     dashbuffer[COLS] = '\0';
  351.     }
  352.     /* Cache the actual sets of display chars to use. */
  353.     if (unitchars == NULL) {
  354.     unitchars = xmalloc(numutypes);
  355.     for_all_unit_types(u) {
  356.         str = u_uchar(u);
  357.         unitchars[u] = (!empty_string(str) ? str[0] : utype_name_n(u, 1)[0]);
  358.     }
  359.     }
  360.     if (terrchars == NULL) {
  361.     terrchars = xmalloc(numttypes);
  362.     for_all_terrain_types(t) {
  363.         str = t_char(t);
  364.         terrchars[t] = (!empty_string(str) ? str[0] : t_type_name(t)[0]);
  365.     }
  366.     }
  367.     unseen_char_1 = unseen_char_2 = ' ';
  368.     str = g_unseen_char();
  369.     if (strlen(str) >= 1) {
  370.     unseen_char_1 = unseen_char_2 = str[0];
  371.     if (strlen(str) >= 2) {
  372.         unseen_char_2 = str[1];
  373.     }
  374.     }
  375.     active = TRUE;
  376.     Dprintf("Successfully opened display!\n");
  377. }
  378.  
  379. void
  380. init_interaction()
  381. {
  382.     Unit *unit;
  383.  
  384.     curunit = NULL;
  385.     find_next_and_look();
  386.     if (curunit) {
  387.     mode = MOVE;
  388.     } else {
  389.     mode = SURVEY;
  390.     move_survey(mvp->vcx, mvp->vcy);
  391.     }
  392.     show_cursor();
  393. }
  394.  
  395. /* Windows in curses are just simple bounding boxes. */
  396.  
  397. struct ccwin *
  398. create_window(x, y, w, h)
  399. int x, y, w, h;
  400. {
  401.     struct ccwin *newwin;
  402.  
  403.     if (x + w > COLS)
  404.       w = COLS - x;
  405.     if (y + h > LINES)
  406.       h = LINES - y;
  407.     DGprintf("Creating %dx%d window at %d,%d\n", w, h, x, y);
  408.  
  409.     newwin = (struct ccwin *) xmalloc(sizeof(struct ccwin));
  410.     newwin->x = x;  newwin->y = y;
  411.     newwin->w = w;  newwin->h = h;
  412.     return newwin;
  413. }
  414.  
  415. /* Generic input character acquisition. */
  416.  
  417. /* (should have a global that indicates whether this is in a modal
  418.    place, then run_game not called on timeout, but waits until out
  419.    of modal thing (perhaps aborts modal dialog automatically, then runs?) */
  420.  
  421. int
  422. wait_for_char()
  423. {
  424.     show_cursor();
  425.     /* Only take 7-bit chars. */
  426.     inpch = getch() & 0177;
  427.     return inpch;
  428. }
  429.  
  430. void
  431. maybe_handle_input(tmout)
  432. int tmout;
  433. {
  434.     char ch;
  435.  
  436.     if (active_display(dside)) {
  437.     if (mode == MOVE) {
  438.         make_current(autonext_unit(dside, curunit));
  439.     }
  440. #ifdef HAVE_SELECT
  441. please somebody write this code
  442. #else
  443.     wait_for_char();
  444. #endif
  445.     /* Program will not work without following due to compiler bug. (?) */
  446.     Dprintf("key is %c", inpch); 
  447.     /* Interpret the input. */
  448.     interpret_input();
  449.     }
  450. }
  451.  
  452. void
  453. interpret_input()
  454. {
  455.     int dir, terr;
  456.  
  457.     if (inpch == REDRAW) {
  458.     /* redraw everything but leave the interaction state unchanged */
  459.     redraw();
  460.     } else if (mode == HELP) {
  461.     interpret_help();
  462.     } else if (isdigit(inpch)) {
  463.     /* Build up a numeric command argument. */
  464.     if (cmdarg < 0) {
  465.         cmdarg = 0;
  466.     } else {
  467.         cmdarg *= 10;
  468.     }
  469.     cmdarg += (inpch - '0');
  470.     sprintf(text1, "Arg: %d", cmdarg);
  471.     show_toplines();
  472.     } else {
  473.     clear_toplines();
  474.     if ((dir = iindex(inpch, dirchars)) >= 0) {
  475.         if (cmdarg < 0)
  476.           cmdarg = 1;
  477.         do_dir_2(dir, cmdarg);
  478.     } else if ((dir = iindex(lowercase(inpch), dirchars)) >= 0) {
  479.         if (cmdarg < 0)
  480.           cmdarg = 9999;
  481.         if (mode == SURVEY)
  482.           cmdarg = 10;
  483.         do_dir_2(dir, cmdarg);
  484.     } else {
  485.         execute_command();
  486.     }
  487.     /* Reset the arg so we don't get confused next time around */
  488.     cmdarg = -1;
  489.     }
  490. }
  491.  
  492. /* Interpret a direction character. */
  493.  
  494. void
  495. do_dir_2(dir, n)
  496. int dir, n;
  497. {
  498.     int nx, ny;
  499.     Unit *unit2;
  500.  
  501.     if (mode == SURVEY) {
  502.     if (!point_in_dir_n(curx, cury, dir, n, &nx, &ny)) {
  503.         xbeep();
  504.         return;
  505.     }
  506.     move_survey(nx, ny);
  507.     } else if (curunit == NULL) {
  508.     return;  /* no beep? */
  509.     } else if (n > 1) {
  510.     set_movedir_task(curunit, dir, n);
  511.     } else {
  512.     if (!interior_point_in_dir(curx, cury, dir, &nx, &ny)) {
  513.         xbeep();
  514.         return;
  515.     }
  516.     advance_into_cell(dside, curunit, nx, ny, unit_at(nx, ny));
  517.     }
  518. }
  519.  
  520. int
  521. auto_attack_on_move(unit, unit2)
  522. Unit *unit, *unit2;
  523. {
  524.     return TRUE;
  525. }
  526.  
  527. void
  528. move_survey(nx, ny)
  529. int nx, ny;
  530. {
  531.     Unit *unit;
  532.  
  533.     if (inside_area(nx, ny)) {
  534.     curx = nx;  cury = ny;
  535.     curunit = NULL;
  536.     /* Look for a top-level unit to become the new current one. */
  537.     for_all_stack(nx, ny, unit) {
  538.         if (unit->side == dside) {
  539.         make_current(unit);
  540.         break;
  541.         }
  542.     }
  543.     put_on_screen(curx, cury);
  544.     } else {
  545.     /* Complain if we're trying to move the cursor offworld. */
  546.     xbeep();
  547.     }
  548. }
  549.  
  550. /* Ensure that given location is visible. */
  551.  
  552. void
  553. put_on_screen(x, y)
  554. int x, y;
  555. {
  556.     if (!in_middle(x, y) /* or x,y is at edge of area */) {
  557.     set_view_focus(mvp, x, y);
  558.     center_on_focus(mvp);
  559.     set_map_viewport();
  560.     show_map();
  561.     show_cursor();
  562.     }
  563.     show_closeup();
  564. }
  565.  
  566. /* Prompt for a yes/no answer with a settable default. */
  567.  
  568. int
  569. ask_bool(question, dflt)
  570. char *question;
  571. int dflt;
  572. {
  573.     char ch;
  574.  
  575.     prevmode = mode;
  576.     mode = PROMPT;
  577.     sprintf(text1, "%s [%s]", question, (dflt ? "yn" : "ny"));
  578.     show_toplines();
  579.     ch = wait_for_char();
  580.     if (dflt ? (lowercase(ch) == 'n') : (lowercase(ch) == 'y'))
  581.       dflt = !dflt;
  582.     mode = prevmode;
  583.     clear_toplines();
  584.     return dflt;
  585. }
  586.  
  587. /* Prompt for a type of a unit from player, maybe only allowing some types
  588.    to be accepted.  Also allow specification of no unit type.  We do this
  589.    by scanning the vector, building a string of chars and a vector of
  590.    unit types, so as to be able to map back when done. */
  591.  
  592. int
  593. ask_unit_type(prompt, possibles)
  594. char *prompt;
  595. short *possibles;
  596. {
  597.     char ch;
  598.     int numtypes = 0, u, type;
  599.  
  600.     for_all_unit_types(u) {
  601.     bvec[u] = 0;
  602.     if (possibles == NULL || possibles[u]) {
  603.         bvec[u] = 1;
  604.         ustr[numtypes] = utype_name_n(u, 1)[0];
  605.         uvec[numtypes] = u;
  606.         numtypes++;
  607.     }
  608.     }
  609.     if (numtypes == 0) {
  610.     return NONUTYPE;
  611.     } else {
  612.     prevmode = mode;
  613.     mode = PROMPT;
  614.     ustr[numtypes] = '\0';
  615.     sprintf(text1, "%s [%s] ", prompt, ustr);
  616.     show_toplines();
  617.     }
  618.     while (1) {
  619.     ch = wait_for_char();
  620.     if (ch == ESCAPE) {
  621.         mode = prevmode;
  622.         clear_toplines();
  623.         return NONUTYPE;
  624.     }
  625.     if (iindex(ch, ustr) >= 0) {
  626.         mode = prevmode;
  627.         clear_toplines();
  628.         return uvec[iindex(ch, ustr)];
  629.     }
  630.     xbeep();
  631.     }
  632. }
  633.  
  634. /* Prompt for a type of a terrain from player, maybe only allowing some types
  635.    to be accepted.  Also allow specification of no terrain type.  We do this
  636.    by scanning the vector, building a string of chars and a vector of
  637.    terrain types, so as to be able to map back when done. */
  638.  
  639. int
  640. ask_terrain_type(prompt, possibles)
  641. char *prompt;
  642. short *possibles;
  643. {
  644.     char ch;
  645.     int numtypes = 0, t, type;
  646.  
  647.     for_all_terrain_types(t) {
  648.     bvec[t] = 0;
  649.     if (possibles == NULL || possibles[t]) {
  650.         bvec[t] = 1;
  651.         ustr[numtypes]
  652.           = (t_char(t) ? t_char(t)[0] : t_type_name(t)[0]);
  653.         uvec[numtypes] = t;
  654.         numtypes++;
  655.     }
  656.     }
  657.     if (numtypes == 0) {
  658.     type = NONTTYPE;
  659.     } else if (numtypes == 1) {
  660.     type = uvec[0];
  661.     bvec[type] = 0;
  662.     } else {
  663.     ustr[numtypes] = '\0';
  664.     sprintf(text1, "%s [%s] ", prompt, ustr);
  665.     show_toplines();
  666.     }
  667.     while (1) {
  668.     ch = wait_for_char();
  669.     if (ch == ESCAPE) {
  670.         clear_toplines();
  671.         return NONTTYPE;
  672.     }
  673.     if (iindex(ch, ustr) >= 0) {
  674.         clear_toplines();
  675.         return uvec[iindex(ch, ustr)];
  676.     }
  677.     xbeep();
  678.     }
  679. }
  680.  
  681. /* Ask for a direction. */
  682.  
  683. int
  684. ask_direction(prompt, dirp)
  685. char *prompt;
  686. int *dirp;
  687. {
  688.     char ch;
  689.  
  690.     prevmode = mode;
  691.     mode = PROMPTXY;
  692.     sprintf(text1, "%s", prompt);
  693.     sprintf(text2, " [direction keys]");
  694.     show_toplines();
  695.     save_cur();
  696.     while (1) {
  697.     ch = wait_for_char();
  698.     if (ch == ESCAPE) {
  699.         restore_cur();
  700.         mode = prevmode;
  701.         clear_toplines();
  702.         show_cursor();
  703.         return FALSE;
  704.     }
  705.     *dirp = iindex(ch, dirchars);
  706.     if (*dirp >= 0) {
  707.         restore_cur();
  708.         mode = prevmode;
  709.         clear_toplines();
  710.         show_cursor();
  711.         return TRUE;
  712.     } else {
  713.         xbeep();
  714.     }
  715.     }
  716. }
  717.  
  718. /* User is asked to pick a position on map.  This will iterate until
  719.    '.' designates the final position. */
  720.  
  721. int
  722. ask_position(prompt, xp, yp)
  723. char *prompt;
  724. int *xp, *yp;
  725. {
  726.     char ch;
  727.     int dir, nx, ny;
  728.  
  729.     prevmode = mode;
  730.     mode = PROMPTXY;
  731.     sprintf(text1, "%s", prompt);
  732.     sprintf(text2, " [direction keys to move, '.' to set]");
  733.     show_toplines();
  734.     save_cur();
  735.     while (1) {
  736.     ch = wait_for_char();
  737.     if (ch == '.') {
  738.         *xp = curx;  *yp = cury;
  739.         restore_cur();
  740.         mode = prevmode;
  741.         clear_toplines();
  742.         show_cursor();
  743.         return TRUE;
  744.     }
  745.     if (ch == ESCAPE) {
  746.         restore_cur();
  747.         mode = prevmode;
  748.         clear_toplines();
  749.         show_cursor();
  750.         return FALSE;
  751.     }
  752.     if ((dir = iindex(ch, dirchars)) >= 0) {
  753.         point_in_dir(curx, cury, dir, &nx, &ny);
  754.         if (inside_area(nx, ny)) {
  755.         curx = nx;  cury = ny;
  756.         put_on_screen(curx, cury);
  757.         show_cursor();
  758.         } else {
  759.         xbeep();
  760.         }
  761.     } else {
  762.         xbeep();
  763.     }
  764.     }
  765. }
  766.  
  767. /* Save away the currently selected position. */
  768.  
  769. void
  770. save_cur()
  771. {
  772.     tmpcurx = curx;  tmpcury = cury;
  773.     tmpcurunit = curunit;
  774. }
  775.  
  776. /* Restore the saved "cur" slots. */
  777.  
  778. void
  779. restore_cur()
  780. {
  781.     curx = tmpcurx;  cury = tmpcury;
  782.     curunit = tmpcurunit;
  783. }
  784.  
  785. /* Read a string from the prompt window.  Deletion is allowed, and a
  786.    cursor is displayed. */
  787.  
  788. int
  789. ask_string(prompt, dflt, strp)
  790. char *prompt, *dflt, **strp;
  791. {
  792.     char ch;
  793.     int done = FALSE, rslt = FALSE;
  794.  
  795.     sprintf(text1, "%s ", prompt);
  796.     reqstrbeg = strlen(text1);
  797.     /* If a default was supplied, add it. */
  798.     if (dflt != NULL)
  799.       strcat(text1, dflt);
  800.     reqstrend = strlen(text1);
  801.     prevmode = mode;
  802.     mode = PROMPT;
  803.     show_toplines();
  804.     while (!done) {
  805.     ch = wait_for_char();
  806.     switch (ch) {
  807.       case '\r':
  808.       case '\n':
  809.         /* Return a copy of the part of the buffer that was typed into. */
  810.         if (strp != NULL)
  811.           *strp = copy_string(text1 + reqstrbeg);
  812.         done = TRUE;
  813.         rslt = TRUE;
  814.         break;
  815.       case ESCAPE:
  816.         xbeep();
  817.         done = TRUE;
  818.         break;
  819.       case BACKSPACE:
  820.       case 0x7f:
  821.         if (reqstrend > reqstrbeg) {
  822.         --reqstrend;
  823.         } else {
  824.         xbeep();
  825.         }
  826.         break;
  827.       default:
  828.         if (reqstrend < BUFSIZE-2) {
  829.         /* Insert the character. */
  830.         (text1)[reqstrend++] = ch;
  831.         } else {
  832.         xbeep();
  833.         }
  834.     }
  835.     /* Make sure we're always properly terminated. */
  836.     (text1)[reqstrend] = '\0';
  837.     show_toplines();
  838.     }
  839.     /* We're done, put everything back the way it was. */
  840.     mode = prevmode;
  841.     clear_toplines();
  842.     show_cursor();
  843.     return rslt;
  844. }
  845.  
  846. /* Ask for a side. */
  847.  
  848. Side *
  849. ask_side(prompt, dflt)
  850. char *prompt;
  851. Side *dflt;
  852. {
  853.     char ch;
  854.     Side *rslt = dflt;
  855.  
  856.     prevmode = mode;
  857.     mode = PROMPT;
  858.     sprintf(text1, "%s ", prompt);
  859.     show_toplines();
  860.     while (1) {
  861.     show_cursor();
  862.     ch = wait_for_char();
  863.     if (ch == ESCAPE) {
  864.         rslt = dflt;
  865.         break;
  866.     }
  867.     if (between('0', ch, '9')) {
  868.         rslt = side_n(ch - '0');
  869.         break;
  870.     }
  871.     if (ch == '\r' || ch == '\n') break;
  872.     xbeep();
  873.     }
  874.     mode = prevmode;
  875.     clear_toplines();
  876.     return rslt;
  877. }
  878.  
  879. int
  880. ask_unit(prompt, unitp)
  881. char *prompt;
  882. Unit **unitp;
  883. {
  884.     *unitp = NULL;
  885.     return FALSE;
  886. }
  887.  
  888. /* Given a unit, make it be the one that we are "looking at". */
  889.  
  890. void
  891. make_current(unit)
  892. Unit *unit;
  893. {
  894.     curunit = unit;
  895.     if (in_play(unit)) {
  896.     curx = unit->x;  cury = unit->y;
  897.     }
  898.     show_closeup();
  899.     show_cursor();
  900. }
  901.  
  902. /* Add 'P' for printing/saving to file (which?). */
  903. /* (Need individual screen scrolling also) */
  904.  
  905. void
  906. interpret_help()
  907. {
  908.     HelpNode *prevhelpnode = cur_help_node;
  909.     extern int first_visible_help_pos, last_visible_help_pos;
  910.  
  911.     switch (inpch) {
  912.       case ' ':
  913.         first_visible_help_pos = last_visible_help_pos;
  914.         show_help();
  915.     break;
  916.       case ESCAPE:
  917.       case 'q':
  918.       case 'Q':
  919.     mode = prevmode;
  920.     redraw();
  921.     break;
  922.       case 'n':
  923.     cur_help_node = cur_help_node->next;
  924.     break;
  925.       case 'p':
  926.     cur_help_node = cur_help_node->prev;
  927.     break;
  928.       case 'b':
  929.     break;
  930.       case 't':
  931.     cur_help_node = topics_help_node;
  932.     break;
  933.       case '?':
  934.     cur_help_node = help_help_node;
  935.     break;
  936.       default:
  937.     xbeep();
  938.     break;
  939.     }
  940.     if (prevhelpnode != cur_help_node) {
  941.     helptopic = cur_help_node->key;
  942.     helpstring = get_help_text(cur_help_node);
  943.         first_visible_help_pos = last_visible_help_pos = 0;
  944.     show_help();
  945.     }
  946. }
  947.  
  948. /* Reading is usually pretty fast, so don't do anything here. */
  949.  
  950. void
  951. announce_read_progress()
  952. {
  953. }
  954.  
  955. /* Announce the start of a time-consuming computation. */
  956.  
  957. void
  958. announce_lengthy_process(msg)
  959. char *msg;
  960. {
  961.     n_seconds_elapsed(0);
  962.     announcemsg = msg;  /* had better be a static string... */
  963. }
  964.  
  965. void
  966. announce_progress(percentdone)
  967. int percentdone;
  968. {
  969.     if (n_seconds_elapsed(1)) {
  970.     if (announcemsg) {
  971.         printf("%s; ", announcemsg);
  972.         announcemsg = NULL;
  973.     }
  974.     if (percentdone > 0) {
  975.         printf(" %d%%", percentdone);
  976.         fflush(stdout);
  977.     }
  978.     announced = TRUE;
  979.     }
  980. }
  981.  
  982. void
  983. finish_lengthy_process()
  984. {
  985.     if (announced || n_seconds_elapsed(1)) {
  986.     if (announcemsg) {
  987.         printf("%s; ", announcemsg);
  988.     }
  989.     printf("; done.\n");
  990.     announced = FALSE;
  991.     }
  992. }
  993.  
  994. /* This is the basic routine to get out of the program - we assume any
  995.    game hacking has been taken care of already. */
  996.  
  997. void
  998. exit_cconq(side)
  999. Side *side;
  1000. {
  1001.     close_displays();
  1002.     /* Leave any commentary on the console. */
  1003.     printf("%s\n", exit_commentary(side));
  1004.     exit(0);
  1005. }
  1006.  
  1007. void
  1008. flush_display_buffers(side)
  1009. Side *side;
  1010. {
  1011.     if (active_display(side)) {
  1012.     refresh();
  1013.     }
  1014. }
  1015.  
  1016. /* A predicate that tests whether our display can validly be written to. */
  1017.  
  1018. int
  1019. active_display(side)
  1020. Side *side;
  1021. {
  1022.     return (side == dside
  1023.         && dside != NULL
  1024.         && side_has_display(dside)
  1025.         && active);
  1026. }
  1027.  
  1028. /* Draw an individual detailed cell, as a row of one, on all maps. */
  1029.  
  1030. void
  1031. update_cell_display(side, x, y, rightnow)
  1032. Side *side;
  1033. int x, y;
  1034. int rightnow;
  1035. {
  1036.     if (active_display(side)) {
  1037.     draw_row(x, y, 1);
  1038.     if (rightnow)
  1039.       refresh();
  1040.     }
  1041. }
  1042.  
  1043. /* Curses updates efficiently, so don't need special routine. */
  1044.  
  1045. void
  1046. update_side_display(side, side2, rightnow)
  1047. Side *side, *side2;
  1048. int rightnow;
  1049. {
  1050.     if (active_display(side)) {
  1051.     show_side_list();
  1052.     if (rightnow)
  1053.       refresh();
  1054.     }
  1055. }
  1056.  
  1057. /* Just change the part of the unit list relevant to the given unit. */
  1058.  
  1059. void
  1060. update_unit_display(side, unit, rightnow)
  1061. Side *side;
  1062. Unit *unit;
  1063. int rightnow;
  1064. {
  1065.     if (active_display(side) && unit != NULL) {
  1066.     if (curunit == unit) {
  1067.         show_closeup();
  1068.         show_map();
  1069.     }
  1070.     show_side_list();
  1071.     show_list();
  1072.     if (rightnow)
  1073.       refresh();
  1074.     }
  1075. }
  1076.  
  1077. void
  1078. update_unit_acp_display(side, unit, rightnow)
  1079. Side *side;
  1080. Unit *unit;
  1081. int rightnow;
  1082. {
  1083.     if (active_display(side)) {
  1084.     }
  1085. }
  1086.  
  1087. void
  1088. update_turn_display(side, rightnow)
  1089. Side *side;
  1090. int rightnow;
  1091. {
  1092.     if (active_display(side)) {
  1093.     show_game_date();
  1094.     if (rightnow)
  1095.       refresh();
  1096.     }
  1097. }
  1098.  
  1099. void
  1100. update_action_display(side, rightnow)
  1101. Side *side;
  1102. int rightnow;
  1103. {
  1104.     if (active_display(side)) {
  1105.     show_side_list();
  1106.     if (rightnow)
  1107.       refresh();
  1108.     }
  1109. }
  1110.  
  1111. void
  1112. update_action_result_display(side, unit, rslt, rightnow)
  1113. Side *side;
  1114. Unit *unit;
  1115. int rslt, rightnow;
  1116. {
  1117.     Action *action = &(unit->act->nextaction);
  1118.  
  1119.     if (active_display(side)) {
  1120.     if (rslt != A_ANY_DONE) {
  1121.         notify(dside, "Action error: %s %s %s!",
  1122.            unit_handle(dside, unit),
  1123.            actiondefns[action->type].name, hevtdefns[rslt].name);
  1124.     } else {
  1125.         switch (action->type) {
  1126.           case A_ATTACK:
  1127.           case A_OVERRUN:
  1128.           case A_FIRE_AT:
  1129.           case A_FIRE_INTO:
  1130.           case A_DETONATE:
  1131.         notify(dside, "%s %s was successful!",
  1132.                unit_handle(dside, unit),
  1133.                actiondefns[action->type].name);
  1134.         }
  1135.         /* Other types of actions are too boring to mention. */
  1136.     }
  1137.     if (rightnow) refresh();
  1138.     }
  1139. }
  1140.  
  1141. void
  1142. update_event_display(side, hevt, rightnow)
  1143. Side *side;
  1144. HistEvent *hevt;
  1145. int rightnow;
  1146. {
  1147.     /* (should add to some sort of history display) */
  1148. }
  1149.  
  1150. void
  1151. update_fire_at_display(side, unit, unit2, m, rightnow)
  1152. Side *side;
  1153. Unit *unit, *unit2;
  1154. int m, rightnow;
  1155. {
  1156.     /* (should flash at target) */
  1157. }
  1158.  
  1159. /* This is for animation of fire-into actions. */
  1160.  
  1161. void
  1162. update_fire_into_display(side, unit, x, y, z, m, rightnow)
  1163. Side *side;
  1164. Unit *unit;
  1165. int x, y, z, m, rightnow;
  1166. {
  1167.     /* (should flash at target) */
  1168. }
  1169.  
  1170. /* Updates to clock need to be sure that display changes immediately. */
  1171.  
  1172. void
  1173. update_clock_display(side, rightnow)
  1174. Side *side;
  1175. int rightnow;
  1176. {
  1177.     if (active_display(side)) {
  1178.     show_clock();
  1179.     show_cursor();
  1180.     if (rightnow)
  1181.       refresh();
  1182.     }
  1183. }
  1184.  
  1185. void
  1186. update_message_display(side, sender, str, rightnow)
  1187. Side *side, *sender;
  1188. char *str;
  1189. int rightnow;
  1190. {
  1191.     if (active_display(side)) {
  1192.     notify(side, "%s", str);
  1193.     if (rightnow)
  1194.       refresh();
  1195.     }
  1196. }
  1197.  
  1198. void
  1199. update_all_progress_displays(str, s)
  1200. char *str;
  1201. int s;
  1202. {
  1203. }
  1204.  
  1205. void
  1206. update_everything()
  1207. {
  1208.     redraw();
  1209. }
  1210.  
  1211. void
  1212. close_displays()
  1213. {
  1214.     if (!active_display(dside))
  1215.       return;
  1216.     clear();
  1217.     refresh();
  1218.     endwin();
  1219.     active = FALSE;
  1220.     DGprintf("Display \"%s\" closed.\n", dside->player->displayname);
  1221. }
  1222.  
  1223. /* An init error needs to have the command re-run. */
  1224.  
  1225. void
  1226. low_init_error(str)
  1227. char *str;
  1228. {
  1229.     fprintf(stderr, "Error: %s.\n", str);
  1230.     fflush(stderr);
  1231. }
  1232.  
  1233. /* A warning just gets displayed, no other action is taken. */
  1234.  
  1235. void
  1236. low_init_warning(str)
  1237. char *str;
  1238. {
  1239.     fprintf(stdout, "Warning: %s.\n", str);
  1240.     fflush(stdout);
  1241. }
  1242.  
  1243. /* A run error is fatal. */
  1244.  
  1245. void
  1246. low_run_error(str)
  1247. char *str;
  1248. {
  1249.     close_displays();
  1250.     fprintf(stderr, "Error: %s.\n", str);
  1251.     fflush(stderr);
  1252.     fprintf(stderr, "Saving the game...");
  1253.     write_entire_game_state(saved_game_filename());
  1254.     fprintf(stderr, " done.\n");
  1255.     fflush(stderr);
  1256.     exit(1);
  1257. }
  1258.  
  1259. /* Runtime warnings are for when it's important to bug the players,
  1260.    usually a problem with Xconq or a game design. */
  1261.  
  1262. void
  1263. low_run_warning(str)
  1264. char *str;
  1265. {
  1266.     if (active_display(dside)) {
  1267.     notify(dside, "Warning: %s; continue? ", str);
  1268.     wait_for_char();
  1269.     } else {
  1270.     low_init_warning(str);
  1271.     }
  1272. }
  1273.  
  1274. void
  1275. printlisp(obj)
  1276. Obj *obj;
  1277. {
  1278.     fprintlisp(stdout, obj);
  1279. }
  1280.  
  1281. /* Even a curses interface can do simple "movies". */
  1282.  
  1283. int
  1284. #ifdef __STDC__
  1285. schedule_movie(Side *side, enum movie_type movie, ...)
  1286. #else
  1287. schedule_movie(side, movie)
  1288. Side *side;
  1289. enum movie_type movie;
  1290. #endif
  1291. {
  1292.     return 0;
  1293. }
  1294.  
  1295. void
  1296. play_movies(sidemask)
  1297. SideMask sidemask;
  1298. {
  1299. }
  1300.